package learn;

import java.util.PriorityQueue;
import java.util.concurrent.*;

/**
 * 线程池
 * 引入线程池是因为再使用时频繁的创建和销毁线程太慢了开销也太大了
 * 所以就可以可以使用线程池，先创建好一些线程再线程池中，再要使用时可以直接去调用
 * 不使用时就等他再那里搁着，
 */

public class threadPool {

    public static void main(String[] args) {
        TimeUnit unit = TimeUnit.SECONDS;
        BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(10);
        ThreadPoolExecutor t = new ThreadPoolExecutor(
                3, 6, 100L , TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
        t.submit(() -> {
            System.out.println("sout");
        });//submit提交任务然后线程池他自己就执行了，等到没有任务了他就阻塞等待

        //java库中的线程池
        /*
        Thread t = new ThreadPoolExecutor(int corePoolSize // 核心线程数 该线程池中最少的线程数，随着线程池创建就创建了
        int maximumPoolSize, //最大的线程数 核心线程数+非核心线程数（自适应）再使用后会把非核心的线程数销毁
        long keepAliveTime, //线程不是越多越好的，这时允许非核心线程的空闲时间，过了之后就销毁了
        TimeUnit unit, //时间枚举 提供了时间单位 天——纳秒
        BlockingQueue<Runnable> workQueue, // 工作队列，阻塞队列
        ThreadFactory threadFactory, //工厂模式，统一构造并初始化线程
        RejectedExecutionHandler handler); // 拒绝策略 当阻塞队列满后就会扩充性的线程，如果线程数大于了最大的线程数，就会使用拒绝策略
        ThreadPoolExecutor.AbortPolicy 丢起这个任务并抛出RejectedExecutionException异常，若不处理这个异常，那么就会影响接下来的任务执行
        ThreadPoolExecutor.CallerRunsPolicy 让调用这个线程的线程自己来完成这个任务
        ThreadPoolExecutor.DiscardOldestPolicy 抛弃最老的任务来完成现在的这个任务
        ThreadPoolExecutor.DiscardPolicy 丢弃这个新任务不执行了
 */

    }
}


/**
 * 实现个线程池
 * 若又任务加入，那么先加入到阻塞对队列中
 * 核心线程在线程池创建是就已经运行，只不过最啊开始的是因为队列为空，处于阻塞状态中等到队列不为空
 * 就读取队列中的元素并执行
 */
class textPoll {
    public static void main(String[] args) {
        ThreadPoolExecutor t = new ThreadPoolExecutor(5, 5, 100l, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        Runnable run = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("休眠线程0.01 秒"+Thread.currentThread().getName()) ;
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        long s = System.currentTimeMillis();
        for (int i = 0; i < 10000; i++) {
            t.submit(run);
        }
        long e = System.currentTimeMillis();
        System.out.println(e - s);//15400
        System.out.println("结束");
    }
    public static void main1(String[] args) {
        BlockQueue_1 BlockQueue_1 = new BlockQueue_1(10);
        myThreadPool pool1 = new myThreadPool(5, 5, new LinkedBlockingQueue<>());
        Runnable run = new Runnable() {
            @Override
            public void run() {
                try {
                    System.out.println("休眠线程0.1 秒"+Thread.currentThread().getName()) ;
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        };
        long s = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            pool1.put(run);
        }

        long e = System.currentTimeMillis();
        System.out.println(e - s);//15400
        System.out.println("结束");
    }
}

class myThreadPool{

    int minThreadCount,maxThreadCount;
    BlockingQueue<Runnable> blockingQueue;
    Thread[] threads;

    public myThreadPool(int min, int max, BlockingQueue<Runnable> blockingQueue) {
        this.minThreadCount = min;
        this.maxThreadCount = max;
//        this.maxTask = maxTask;换成阻塞队列，这样任务就能无限犯了
        this.blockingQueue = blockingQueue;
        threads = new Thread[max];
        for (int i = 0; i < min; i++) {
            threads[i] = new Thread(() -> {// 创建一个新的线程
                while (true) {
                    Runnable run = null;
                    synchronized (blockingQueue) {//
                        while (blockingQueue.isEmpty()) {
                            try {
//                                System.out.println("队列空了");
                                blockingQueue.wait();
                            } catch (InterruptedException e) {
                                throw new RuntimeException(e);
                            }
                        }
                        //不为空就给执行
                        run = blockingQueue.poll();
                        blockingQueue.notify();
                    }
                    run.run();

                }
            }, "线程——" + i);
            threads[i].start();
        }
    }

    public void put(Runnable runnable){
        synchronized (blockingQueue) {
            //这是应为有数组大小的限制
//            while (blockingQueue.size() == maxTask) {
//                try {
////                    System.out.println("队列满了");
//                    blockingQueue.wait();
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
//            }
            //有任务直接放就行
            blockingQueue.add(runnable);
            blockingQueue.notify();
        }
    }
}

/**
 * 定时器
 * 自动在指定的时间过后执行对应的任务
 * 有一个Task类将任务和执行是间组织起来
 * 按任务的时间建立一个小根堆，然后每次都出堆顶元素并执行就解决了
 */
class textTimer {
    public static void main(String[] args) {
//        Object o = new Runnable() {
//        };
        My_Timer t = new My_Timer();
        for (int i = 0; i < 10; i++) {
            int tmp = i ;
            task t1 = new task(() -> {
//                try {
                    System.out.println(tmp * 2+ " 秒后执行");
//                    Thread.sleep(tmp * 1000);
//                } catch (InterruptedException e) {
//                    throw new RuntimeException(e);
//                }
            });
            t.schedule(t1, i * 1000*2);
        }
        System.out.println("main end");
    }

    public synchronized void tt() {
        try {
            wait();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
}

class task implements Comparable<task> {
    long time;
    Runnable run;

    task(Runnable r) {
        run = r;
    }
    @Override
    public int compareTo(task o) {
        return (int)(this.time - o.time);
    }
}

class My_Timer {

    private PriorityQueue<task> queue = new PriorityQueue<>();

    public My_Timer() {
        //创建一个线程，一直运行用等到时间够了就去运行方法
        Thread t1 = new Thread(() -> {
            while (true) {
                synchronized (queue) {
//                    wait();
                    while (queue.isEmpty()) {
                        try {
                            System.out.println("对列为空");
                            queue.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    task t = queue.peek();
                    while (t.time > System.currentTimeMillis()) {
                        try {
                            //如果不加queue这个对象 单使用wait的话他对应的锁对象是
                            System.out.println(t.time);
                            queue.wait(t.time - System.currentTimeMillis());
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }
                    t.run.run();//时间到了运行
                    queue.poll();
                }
            }
        });
        t1.start();
    }

    public void schedule(task t, long time) {
        synchronized (queue) {
            queue.add(t);
            t.time = System.currentTimeMillis() + time;//已当前的时间
            queue.notify();
        }
    }
}


